package moltencore.game.loader;

import moltencore.game.Cannon;
import moltencore.game.CannonData;
import spark.math.Vector2;
import spark.utility.IncrementalShortIdFactory;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;

import moltencore.game.bubble.Type;
import moltencore.game.bubble.Bubble;
import moltencore.game.Grid;
import moltencore.game.collision.VerticalLine;
import moltencore.game.collision.HorizontalLine;

public class Level {
	public static final int UNIT_PIXEL_RATIO = 32;
	private static final String UNTITLED = "untitled";
	public static final String EXTENSION = "bbl";

	private String name;
	private LinkedList<LevelSprite> levelSprites = new LinkedList<LevelSprite>();
	private Grid attachedBubbles = new Grid();
	private Grid pushBubbles = new Grid();
	private Grid fillBubbles = new Grid();
	private HashMap<Integer, CannonData> cannonData = new HashMap<Integer, CannonData>();
	private Vector2 scorePosition;
	private Vector2 nickPosition;
	private Vector2 clockPosition;

	private Vector2 resultPosition;

	private IncrementalShortIdFactory bubbleIdFactory = new IncrementalShortIdFactory();
	private LinkedList<VerticalLine> verticalLines = new LinkedList<VerticalLine>();
	private LinkedList<HorizontalLine> horizontalLines = new LinkedList<HorizontalLine>();
	private LinkedList<HorizontalLine> restrictedAreas = new LinkedList<HorizontalLine>();
	private LinkedList<HorizontalLine> criticalAreas = new LinkedList<HorizontalLine>();
	private LinkedList<HorizontalLine> killAreas = new LinkedList<HorizontalLine>();

	public Level() {
		this(UNTITLED);
	}

	public Level(String name) {
		this.name = name;
		bubbleIdFactory.getNextId();
	}

	public void addSprite(LevelSprite sprite) {
		levelSprites.add(sprite);
	}

	public LinkedList<LevelSprite> getLevelSprites() {
		return levelSprites;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setCannonPosition(Vector2 position, int index) {
		if(!cannonData.containsKey(index)) {
			cannonData.put(index, new CannonData(index, new Vector2(), new Vector2(), new Vector2()));
		}
		cannonData.get(index).getPosition().copy(position);
	}

	public void setCannonNextPosition(Vector2 position, int index) {
		if(!cannonData.containsKey(index)) {
			cannonData.put(index, new CannonData(index, new Vector2(), new Vector2(), new Vector2()));
		}
		cannonData.get(index).getNextPosition().copy(position);
	}

	public void setCannonTarget(Vector2 target, int index) {
		if(!cannonData.containsKey(index)) {
			cannonData.put(index, new CannonData(index, new Vector2(), new Vector2(), new Vector2()));
		}
		cannonData.get(index).getTarget().copy(target);
	}

	public Vector2 getNickPosition() {
		return nickPosition;
	}

	public void setNickPosition(Vector2 position) {
		if(nickPosition == null) {
			nickPosition = new Vector2(position);
			return;
		}
		this.nickPosition.copy(position);
	}

	public Vector2 getClockPosition() {
		return clockPosition;
	}

	public void setClockPosition(Vector2 position) {
		if(clockPosition == null) {
			clockPosition = new Vector2(position);
			return;
		}
		this.clockPosition.copy(position);
	}

	public void addBubble(Type type, int gridPositionX, int gridPositionY) {
		attachedBubbles.clearBubble(gridPositionX, gridPositionY);
		Bubble bubble = new Bubble(type, (short) -bubbleIdFactory.getNextId());
		attachedBubbles.snapToGrid(bubble, gridPositionX, gridPositionY);
	}

	public void addPushBubble(int gridPositionX, int gridPositionY) {
		pushBubbles.clearBubble(gridPositionX, gridPositionY);
		Bubble bubble = new Bubble(null, (short) 0);
		pushBubbles.snapToGrid(bubble, gridPositionX, gridPositionY);
	}

	public void addFillBubble(int gridPositionX, int gridPositionY) {
		fillBubbles.clearBubble(gridPositionX, gridPositionY);
		Bubble bubble = new Bubble(null, (short) 0);
		fillBubbles.snapToGrid(bubble, gridPositionX, gridPositionY);
	}

	public Vector2 getCannonPosition(int index) {
		CannonData cd = cannonData.get(index);
		if(cd == null) {
			return null;
		}
		return cd.getPosition();
	}

	public Vector2 getCannonNextPosition(int index) {
		CannonData cd = cannonData.get(index);
		if(cd == null) {
			return null;
		}
		return cd.getNextPosition();
	}

	public Vector2 getCannonTarget(int index) {
		CannonData cd = cannonData.get(index);
		if(cd == null) {
			return null;
		}
		return cd.getTarget();
	}

	public LinkedList<Bubble> getAttachedBubbles() {
		if(attachedBubbles == null) {
			return null;
		}
		return attachedBubbles.getBubbles();
	}

	public LinkedList<Bubble> getFillBubbles() {
		if(fillBubbles == null) {
			return null;
		}
		return fillBubbles.getBubbles();
	}

	public LinkedList<VerticalLine> getVerticalLines() {
		return verticalLines;
	}

	public LinkedList<HorizontalLine> getHorizontalLines() {
		return horizontalLines;
	}

	public void add(VerticalLine verticalLine) {
		verticalLines.add(verticalLine);
	}

	public void addRestrictedArea(HorizontalLine horizontalLine) {
		restrictedAreas.add(horizontalLine);
	}

	public void addCriticalArea(HorizontalLine horizontalLine) {
		criticalAreas.add(horizontalLine);
	}

	public void addKillArea(HorizontalLine horizontalLine) {
		killAreas.add(horizontalLine);
	}

	public void add(HorizontalLine horizontalLine) {
		horizontalLines.add(horizontalLine);
	}

	public LinkedList<HorizontalLine> getRestrictedAreas() {
		return restrictedAreas;
	}

	public LinkedList<HorizontalLine> getCriticalAreas() {
		return criticalAreas;
	}

	public LinkedList<HorizontalLine> getKillAreas() {
		return killAreas;
	}

	public void setScorePosition(Vector2 position) {
		if(scorePosition == null) {
			scorePosition = new Vector2(position);
			return;
		}
		this.scorePosition.copy(position);
	}

	public void setResultPosition(Vector2 position) {
		if(resultPosition == null) {
			resultPosition = new Vector2(position);
			return;
		}
		this.resultPosition.copy(position);
	}

	public LinkedList<Bubble> getPushBubbles() {
		if(pushBubbles == null) {
			return null;
		}
		return pushBubbles.getBubbles();
	}

	public Vector2 getScorePosition() {
		return scorePosition;
	}

	public Vector2 getResultPosition() {
		return resultPosition;
	}

	public Collection<CannonData> getCannonData() {
		return cannonData.values();
	}
}
